﻿using System;
using System.Collections.Generic;
using System.Reflection;
using MugenInjection.Delegates;

namespace MugenInjection.Interface
{
    /// <summary>
    ///     Represents the reflection access provider to members access.
    /// </summary>
    public interface IReflectionAccessProvider
    {
        /// <summary>
        ///     Gets a delegate to create an object.
        /// </summary>
        /// <param name="constructorInfo">
        ///     The specified <see cref="ConstructorInfo" />.
        /// </param>
        /// <returns>
        ///     An instance of <see cref="ActivatorDelegate" />
        /// </returns>
        ActivatorDelegate GetActivatorDelegate(ConstructorInfo constructorInfo);

        /// <summary>
        ///     Gets a delegate to set a value in the specified <see cref="MemberInfo" />.
        /// </summary>
        /// <typeparam name="TTarget">Type of the target.</typeparam>
        /// <param name="memberInfo">
        ///     The specified <see cref="MemberInfo" />.
        /// </param>
        /// <returns>
        ///     An instance of <see cref="SetterDelegate{TTarget}" />
        /// </returns>
        SetterDelegate<TTarget> GetAssignMemberDelegate<TTarget>(MemberInfo memberInfo) where TTarget : class;

        /// <summary>
        ///     Gets a delegate to set specified value in the specified <see cref="MemberInfo" /> in a value type target, can be used with reference type.
        /// </summary>
        /// <typeparam name="TTarget">Type of the target.</typeparam>
        /// <param name="memberInfo">
        ///     The specified <see cref="MemberInfo" />.
        /// </param>
        /// <returns>
        ///     An instance of <see cref="SetterDelegate{TTarget}" />
        /// </returns>
        SetterValueTypeDelegate<TTarget> GetAssignValueMemberDelegate<TTarget>(MemberInfo memberInfo);

        /// <summary>
        ///     Gets a delegate to get a value in the specified <see cref="MemberInfo" />
        /// </summary>
        /// <typeparam name="TTarget">Type of the target.</typeparam>
        /// <typeparam name="T">Type of the target.</typeparam>
        /// <param name="memberInfo">
        ///     The specified <see cref="MemberInfo" />.
        /// </param>
        GetterDelegate<TTarget, T> GetGetterMemberDelegate<TTarget, T>(MemberInfo memberInfo);

        /// <summary>
        ///     Gets a delegate to call specified <see cref="MethodInfo" />.
        /// </summary>
        /// <param name="methodInfo">
        ///     The specified <see cref="MethodInfo" />
        /// </param>
        /// <returns>
        ///     An instance of <see cref="InvokeMethodDelegate{TTarget}" />
        /// </returns>
        InvokeMethodDelegate<TTarget> GetInvokeMethodDelegate<TTarget>(MethodInfo methodInfo)
            where TTarget : class;

        /// <summary>
        ///     Gets a delegate to call specified <see cref="MethodInfo" /> in a value type target, can be used with reference type.
        /// </summary>
        /// <param name="methodInfo">
        ///     The specified <see cref="MethodInfo" />
        /// </param>
        /// <returns>
        ///     An instance of <see cref="InvokeMethodDelegate{TTarget}" />
        /// </returns>
        InvokeMethodValueTypeDelegate<TTarget> GetInvokeMethodValueTypeDelegate<TTarget>(MethodInfo methodInfo);

        /// <summary>
        ///     Converts the Func{object[], object} to the specified delegate type.
        /// </summary>
        /// <param name="proxyDelegate">The specified proxy method.</param>
        /// <param name="delegateType">The specified delegate type.</param>
        /// <returns>An instance of delegate type.</returns>
        Delegate ConvertToProxyDelegate(Func<object[], object> proxyDelegate, Type delegateType);

        /// <summary>
        ///     Returns a weak-reference version of a delegate.
        /// </summary>
        /// <param name="originalAction">The delegate to convert to weak referencing.</param>
        /// <param name="unsubcribeDelegate">The unregister action to invoke if the target is garbage collected.</param>
        /// <returns>A weak referencing delegate.</returns>
        Delegate ConvertToWeakDelegate(Delegate originalAction, Action<Delegate> unsubcribeDelegate);

        /// <summary>
        /// Finds the weak-delegate use a original delegate in the specified array of delegate.
        /// </summary>
        /// <param name="originalAction">The original delegate to find weak delegate.</param>
        /// <param name="delegates">The specified array of delegate</param>
        /// <returns>An instance of delegate.</returns>
        Delegate FindWeakDelegateByOriginalDelegate(Delegate originalAction, IList<Delegate> delegates);
    }
}